# 导入所需库
from tkinter import *
import random
from tkinter import messagebox

class main:
    # 定义一个类，继承 tkinter 的 Button
    # 用来保存按钮的状态和在网格布局中的位置
    class minebtn(Button):
        def __init__(self,master,xy,**kw):
            Button.__init__(self,master,**kw)
            self.xy = xy
            self._state = 0
            # 状态
            # 0: 未点开
            # 1: 已点开
            # 2: 标记
            # 3: 问号
            
    def __init__(self):
        # 定义规格及雷数
        self.width = 28
        self.height = 28
        self.minenum = 80
        # Windows 7 默认的三种规格和雷数
        # 9*9,10
        # 16*16,40
        # 16*32,99
        
        self.rest = self.minenum    # 剩余未标记的雷
		
		# 雷数的颜色
        self.colorlist = ['green',	# 绿色
                          'DodgerBlue',	# 浅蓝色
                          'DarkOrange1',# 橙色
                          'blue',	# 蓝色
                          'red',	# 红色
                          'Chocolate4',	# 棕色
                          'grey',	# 灰色
                          'black']	# 黑色
        
        self.setgui()

    def setgui(self):

        # GUI界面

        self.root = Tk()
        self.root.title('扫雷')

        self.restlabel = Label(self.root,text=f'剩余：{self.minenum}')
        self.restlabel.grid(row=0,column=0,columnspan=3)

        self.mineplace = random.sample(range(self.width*self.height),self.minenum)  # 随机抽取雷
        self.mineplace = [(x%self.width,x//self.height) for x in self.mineplace]    # 将雷的序号转变为坐标

        self.mines = {}

        for y in range(self.height):
            for x in range(self.width):
                self.mines[(x,y)] = self.minebtn(self.root,xy=(x,y),font=('黑体',8,'bold'),width=2,bd=1,relief='ridge')
                self.mines[(x,y)].bind('<ButtonRelease-1>',lambda event:self._open(event.widget))   # 左键单击点开
                self.mines[(x,y)].bind('<ButtonRelease-3>',lambda event:self.make(event.widget))    # 右键单击事件
                self.mines[(x,y)].grid(row=y+1,column=x,sticky='nswe')

        self.root.mainloop()

    # 点开
    def _open(self, widget):
        xy = widget.xy
        x, y = xy  # 获取当前按钮的坐标

        # 如果是雷则显示全部雷的位置
        if widget.xy in self.mineplace:
            self.showmine()
            return

        # 如果已经点开了就什么也不做
        if widget._state == 1:
            return
        
        widget.configure(relief='flat',bg='white')  # 更改当前按钮的样式
        widget._state = 1   # 按钮状态设为点开

        # 获取周围八个格子的坐标，但不立即过滤状态
        around_coords = [(x-1,y-1),(x,y-1),(x+1,y-1),(x-1,y),(x+1,y),(x-1,y+1),(x,y+1),(x+1,y+1)]

        # 计算周围雷数
        _sum = sum(1 for o, p in around_coords if 0 <= o < self.width and 0 <= p < self.height and self.mines[(o, p)].xy in self.mineplace)

        # 显示雷数
        widget['text'] = _sum if _sum > 0 else ''  # 如果周围无雷则不显示数字
        widget['fg'] = self.colorlist[_sum-1] if _sum > 0 else 'black'  # 设置颜色

        # 如果周围没有雷则打开周围未标记的格子
        if _sum == 0:
            for i, j in around_coords:
                if 0 <= i < self.width and 0 <= j < self.height and self.mines[(i,j)]._state == 0:
                    self._open(self.mines[(i,j)])

        if self.check_win():
            self.win_game()

    # 右键单击设置标记/问号
    def make(self,widget):
        string = {0:'',2:'♀',3:'?'}
        
        if widget._state == 0:
            widget._state = 2
            widget['text'] = string[2]
            self.rest -= 1
            self.restlabel['text'] = f'剩余：{self.rest}'
            
        elif widget._state == 2:
            widget._state = 3
            widget['text'] = string[3]
            self.rest += 1
            self.restlabel['text'] = f'剩余：{self.rest}'
            
        elif widget._state == 3:
            widget._state = 0
            widget['text'] = string[0]

    # 如果踩到雷，显示所有的雷
    def showmine(self):
        for i, j in self.mineplace:
            self.mines[(i,j)].configure(text='ி',fg='red')

    # 在main类内部添加以下方法
    def check_win(self):
        # 遍历所有方格
        for y in range(self.height):
            for x in range(self.width):
                # 如果发现有非雷方格未被点开，则返回False，表示未获胜
                if self.mines[(x, y)]._state != 1 and (x, y) not in self.mineplace:
                    return False
        
        # 所有非雷方格都被点开，游戏胜利
        return True


    # 添加一个展示胜利信息的方法
    def win_game(self):
        # 这里可以根据需要添加更多胜利后的处理逻辑，比如弹出提示框、更新GUI界面等

            # 更新GUI界面以反映胜利状态
        # 例如，可以改变所有未点击的按钮样式，或者禁用所有按钮防止进一步操作
        for y in range(self.height):
            for x in range(self.width):
                btn = self.mines[(x, y)]
                if btn._state == 0:  # 如果按钮还未被点击过
                    btn.configure(state="disabled", bg="SystemButtonFace")  # 禁用按钮并恢复默认背景色
                elif btn.xy in self.mineplace:  # 对于雷的按钮，也可以做些特殊标记
                    btn.configure(bg="lightgreen")  # 示例：将雷按钮变为浅绿色

        # 可能还想要更新剩余雷数标签，显示胜利信息
        self.restlabel['text'] = "胜利！"

        messagebox.showinfo("游戏结果", "恭喜您，赢得了游戏！")

                    
main()


